package com.firmail.controller;

import com.firmail.cloud.mcenter.service.impl.MockCenterCloudServImpl;
import com.firmail.config.DsProperties;
import com.firmail.dao.MockApiInfoMapper;
import com.firmail.entity.MockApiInfo;
import com.firmail.entity.MockApiInfoExample;
import com.firmail.entity.vo.MockInfoVO;
import com.firmail.enumeration.impl.DataTypeEnum;
import com.firmail.enumeration.impl.MockTypeEnum;
import com.firmail.exception.FieldValidationException;
import com.firmail.exception.cloud.ParamsInvalidException;
import com.firmail.exception.type.ExceptionType;
import com.firmail.func.Converter;
import com.firmail.mock.center.api.vo.MockMetadata;
import com.firmail.model.Pager;
import com.firmail.model.ResultObject;
import com.firmail.model.WrapText;
import com.firmail.service.CheckDataFormatService;
import com.firmail.service.DownloadInfoService;
import com.firmail.service.impl.JsonDataProcessImpl;
import com.firmail.service.impl.MockApiInfoServiceImpl;
import com.firmail.utils.Function;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

@Api("MockFacadeController")
@Controller
@Slf4j
@RequestMapping(value = "/", method = {RequestMethod.GET, RequestMethod.POST}, produces = {"application/json;charset=utf-8"})
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class FirmailController {
    //@Autowired
    private final DownloadInfoService downloadInfoService;

    private final CheckDataFormatService checkDataFormatService;

    private final MockCenterCloudServImpl mccsImpl;

    private final JsonDataProcessImpl jsonDataProcess;

    private final MockApiInfoServiceImpl mockApiInfoService;

    private final DsProperties properties;

    private void validateInput(MockInfoVO mVO) {
        if (mVO != null) {
            if (StringUtils.isBlank(mVO.getDataType())
                    || StringUtils.isBlank(mVO.getDataType())
                    || StringUtils.isBlank(mVO.getReqAddr()))
                throw new FieldValidationException(ExceptionType.INVALID_PARAMETER_EXCEPTION);

        }
    }

    /**
     * check validation of input
     *
     * @param method
     * @return
     */
    private String validateRequestMethod(MockTypeEnum method) {

        String reqMethod;
        switch (method) {
            case MOCK_GET:
                reqMethod = MockTypeEnum.MOCK_GET.getInfo();
                break;
            case MOCK_POST:
                reqMethod = MockTypeEnum.MOCK_POST.getInfo();
                break;
            case MOCK_PUT:
                reqMethod = MockTypeEnum.MOCK_PUT.getInfo();
                break;
            case MOCK_DELETE:
                reqMethod = MockTypeEnum.MOCK_DELETE.getInfo();
                break;
            default:
                throw new FieldValidationException(ExceptionType.INVALID_PARAMETER_EXCEPTION);
                //break;
        }
        return reqMethod;
    }


    private String validateDataType(DataTypeEnum dataType) {

        switch (dataType) {
            case JSON:
                return dataType.getName();
            case XML:
                return dataType.getName();
            default:
                throw new FieldValidationException(ExceptionType.INVALID_PARAMETER_EXCEPTION);
        }

    }

    /*private MockMetadata getMetadata(MockApiInfo mockApiInfo) {
        //String pData= jsonDataProcess.transferJson(data);
        MockMetadata metadata = new MockMetadata();
        metadata.setRelativePath(mockApiInfo.getReqAddr());
        metadata.setReqMethod(mockApiInfo.getReqMethod());
        metadata.setDataType("json");
        metadata.setData(jsonDataProcess.processData(data));
        return metadata;
    }

    private String invokeAndCreate(MockMetadata metadata) {
        return mccsImpl.createMock(metadata);
    }*/

    private int persistMockApiInfo(MockInfoVO mVO) {
        //MockApiInfo mockApiInfo =new MockApiInfo();
        mVO.setCreatetime(new Date());
        //mockApiInfo.setCreator("dzs");
        //mockApiInfo.setData(jdata);
        //mockApiInfo.setDataType(dataType);
        //mockApiInfo.setMajor(userName);
        //mockApiInfo.setName(mockApiInfo.getReqAddr());
        //mockApiInfo.setReqAddr(requestAdress);
        //mockApiInfo.setReqMethod(reqMethod);
        return mockApiInfoService.saveOrUpdateMockData(mVO);
    }

    private final String resultRegex = "(.*)>>>The OPS - create_file(.*)";

    @ApiOperation(value = "mock portal- check input pattern & persist mock data.", notes = "mock入口方法")
    @ApiImplicitParam("mockinfo")
    @RequestMapping(value = "checkDataFormat", consumes = {"application/json;charset=utf-8"})
    @ResponseBody
    public ResultObject<?> checkDataFormat(@RequestBody MockInfoVO mVO) throws IOException {
        //check non-blank options
        validateInput(mVO);
        //create converter
        Converter<String, Integer> c = Integer::valueOf;
        MockTypeEnum method = Converter.getMethod(c.convert(mVO.getReqMethod()));
        //validate the request method
        String reqMethod = validateRequestMethod(method);
        //check the input of data type, such as JSON
        DataTypeEnum dataTypeEnum = Converter.getDataType(c.convert(mVO.getDataType()));
        String dataType = validateDataType(dataTypeEnum);

        ResultObject ro=null;
        //Assemble the mock data
        MockMetadata metadata = new MockMetadata();
        metadata.setRelativePath(mVO.getReqAddr());
        metadata.setReqMethod(reqMethod);
        metadata.setDataType(dataType);
        if (DataTypeEnum.JSON.equals(dataTypeEnum)) { //json数据
            //persistMockApiInfo(mVO);
            metadata.setData(jsonDataProcess.processData(mVO.getData()));
            String retText =mccsImpl.createMock(metadata);

            //could it have a prerequisites ?
            //Linux Platform might execute it successfully?
            if (retText!=null&&Pattern.matches(resultRegex, retText)) {
                persistMockApiInfo(mVO);
                ro = new ResultObject<>(getWrapInfo(StringUtils.trim(mVO.getReqAddr()), retText));
            }
            else if (mccsImpl.createXPMock(metadata)){
                persistMockApiInfo(mVO);
                ro= new ResultObject<>(getWrapInfo(StringUtils.trim(mVO.getReqAddr()),null));
            }

        } else if (DataTypeEnum.XML.equals(dataTypeEnum)) {//xml数据

           if (checkDataFormatService.checkXML(mVO.getData())){
               metadata.setData(StringUtils.trim(mVO.getData()));
               if (mccsImpl.createXPMock(metadata)){
                   persistMockApiInfo(mVO);
                   ro= new ResultObject<>(getWrapInfo(StringUtils.trim(mVO.getReqAddr()),null));
               }
           }
        } else {

           throw new ParamsInvalidException();
        }
        return ro;
    }


    @RequestMapping(value = "checkDataFormat-1", consumes = {"application/json"})
    @ResponseBody
    public ResultObject<Object> checkDataFormat(HttpServletRequest request) {
        int type = Function.parseInt(request.getParameter("dataType"), 0);
        if (type == 0) {
            return new ResultObject<>(-1, "数据类型不能为空！");
        }
        String data = Function.notNull(request.getParameter("dataContent"), "");
        if (StringUtils.isEmpty(data)) {
            return new ResultObject<>(-1, "数据内容不能为空！");
        }
        String userName = request.getParameter("userName");
        String requestAdress = request.getParameter("requestAdress");
        String requestType = request.getParameter("requestType");

        Converter<String, Integer> c = Integer::valueOf;
        String reqMethod = null;
        MockTypeEnum method = Converter.getMethod(c.convert(requestType));
        switch (method) {
            case MOCK_GET:
                reqMethod = MockTypeEnum.MOCK_GET.getInfo();
                break;
            case MOCK_POST:
                reqMethod = MockTypeEnum.MOCK_POST.getInfo();
                break;
            case MOCK_PUT:
                reqMethod = MockTypeEnum.MOCK_PUT.getInfo();
                break;
            case MOCK_DELETE:
                reqMethod = MockTypeEnum.MOCK_DELETE.getInfo();
                break;
            default:
                break;
        }

        if (MockTypeEnum.MOCK_POST.equals(method)) { //json数据
            try {
                //JSONObject jsonStr= JSONObject.parseObject(data);
                //String pData= jsonDataProcess.transferJson(data);
                MockMetadata metadata = new MockMetadata();
                metadata.setRelativePath(requestAdress);
                metadata.setReqMethod(reqMethod);
                metadata.setDataType("json");
                String jdata = jsonDataProcess.processData(data);
                metadata.setData(jsonDataProcess.processData(data));
                MockInfoVO mockApiInfo = new MockInfoVO();
                mockApiInfo.setCreatetime(new Date());
                mockApiInfo.setCreator("fghj");
                mockApiInfo.setData(jdata);
                mockApiInfo.setDataType("json");
                mockApiInfo.setMajor(userName);
                mockApiInfo.setName(requestAdress);
                mockApiInfo.setReqAddr(requestAdress);
                mockApiInfo.setReqMethod(reqMethod);
                mockApiInfoService.createApiData(mockApiInfo);
                return new ResultObject<>(mccsImpl.createMock(metadata));
            } catch (Exception e) {
                return new ResultObject<>(-1, "这不是一个json格式的数据！" + e.getMessage());
            }

        } else if (2 == type) {//xml数据
            //return checkDataFormatService.checkXML(data);
            return null;
        } else {
            return new ResultObject<>(-1, "请传入正确的type类型！");
        }
    }

    /**
     * 页面跳转
     */
    @RequestMapping("index")
    public String toCheckDataFormatPage() {
        return "checkDataFormat";
    }

    /**
     * 页面跳转
     */
    @RequestMapping("list")
    public String toHistoryList() {
        return "history-list";
    }


    @RequestMapping(value = "get/history/list", consumes = {"application/json;charset=utf-8"})
    @ResponseBody
    public ResultObject<?> getHistoryList() {

        return new ResultObject<>(mockApiInfoService.getAPIDataByOrder(new MockInfoVO(), 0, 20));
    }

    private final MockApiInfoMapper mockApiInfoMapper;

    //Just for PageHelper test
    @GetMapping(value = "test/infos")
    @ResponseBody
    public PageInfo<MockApiInfo> getUsers() {
        PageHelper.startPage(1, 20);
        List<MockApiInfo> users = mockApiInfoMapper.selectByExampleWithRowbounds(new MockApiInfoExample(), new RowBounds(0, 20));
        PageInfo<MockApiInfo> pageInfo = new PageInfo<>(users);
        return pageInfo;
    }

    //should be wrapped by ResultObject
    @RequestMapping(value = "hbn/getdata", consumes = {"application/json;charset=utf-8"})
    @ResponseBody
    public Pager<MockInfoVO> getData(@RequestBody MockInfoVO searchModel, HttpServletResponse response,
                                     @RequestParam(defaultValue = "1") int pageNum,
                                     @RequestParam(defaultValue = "10") int pageSize) {
        //        //不用缓存
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        //超时0
        response.addDateHeader("Expires", 0);
        // 组装查询条件
        Pager<MockInfoVO> pager = mockApiInfoService.getPageVOByModel(searchModel, pageNum, pageSize);
        return pager;
    }

    @GetMapping(value = "prop")
    @ResponseBody
    public ResultObject<?> getTestData() {
        return new ResultObject<>(properties);
    }
    private WrapText getWrapInfo(String path, String report){
        WrapText tx = new WrapText();
        tx.setCallbackReport(report);
        tx.setConfigIP(properties.getConfigIP());
        if (path!=null&&!path.endsWith("/"))
            path=path+"/";
        if (path!=null&&!path.startsWith("/"))
            path="/"+path;
        tx.setSimulatorPath(path);
        tx.setSimulatorPort(properties.getSimulatorPort());
        tx.setSimulatorUrl(tx.getConfigIP()+":"+tx.getSimulatorPort()+tx.getSimulatorPath());

        return tx;
    }
    @GetMapping(value = "wp")
    @ResponseBody
    public ResultObject<?> getWrapTestData() {

        return new ResultObject<>(getWrapInfo("/ois-hr/kl",null));
    }
}
